/**
 * ts实现Promise
 */

enum PStatus{
    PENDING="pending",
    REJECT="rejectd",
    RESOLVE="resolved",
}


interface CallBack{
    onResolve()
    onReject()
}

type CB = (c:any)=>_Promise

class _Promise{

    private data:any = undefined
    private callback:CallBack|undefined = undefined
    private status:PStatus = PStatus.PENDING 
    constructor(private executor){
        
        //使用箭头函数处理this的问题
        const resolve = data=>{
            if(this.status!=PStatus.PENDING) return
            this.status = PStatus.RESOLVE
            this.data = data
    
            if(typeof this.callback !='undefined'){
                setTimeout(()=>{
                    this.callback.onResolve()
                })
            }
        }

        const reject= reason=>{
            if(this.status!=PStatus.PENDING) return
            this.status = PStatus.REJECT
            this.data = reason
    
            if(typeof this.callback !='undefined'){
                setTimeout(()=>{
                    this.callback.onReject()
                })
            }
        }

        try{
            executor(resolve,reject)
        }catch(err){
            reject(err)
        }
    }
    then(onResolve=data=>data,onReject=reason=>reason):_Promise{
        //对onResolve onReject进行包装
        const handler =(callback:Function,resolve:Function,reject:Function)=>{
            try{
                let res = callback(this.data)
                if(res instanceof _Promise){
                    res.then(data=>resolve(data),reason=>reject(reason))
                }else{
                    resolve(res)
                }
            }catch(err){
                reject(err)
            }
        }

        return new _Promise((resolve,reject)=>{
            if(this.status==PStatus.PENDING){
                this.callback = {
                    onResolve(){
                        handler(onResolve,resolve,reject)   
                    },
                    onReject(){
                        handler(onReject,resolve,reject)
                    }
                }
            }else if(this.status==PStatus.RESOLVE){
                handler(onResolve,resolve,reject)
            }else{
                handler(onReject,resolve,reject)
            }
        })
    }

    catch(onReject=reason=>reason):_Promise{
        return this.then(undefined,onReject)
    }

    static resolve(value):_Promise{
        if(value instanceof _Promise) return value
        else if (!value&&!value.then) return new _Promise(value.then)
        return new _Promise(resolve=>resolve(value))
    }

    static reject(value):_Promise{
        return new _Promise((_,reject)=>{
            reject(value)
        })
    }

    static all(promises:any[]):_Promise{
        if(promises.length==0) return _Promise.resolve([])
        let v  = []
        let cnt = 0        
        return new _Promise((resolve,reject)=>{
            for(let i=0;i<promises.length;i++){
                _Promise.resolve(promises[i]).then(data=>{
                    v[i] = data
                    cnt++
                    if(cnt==promises.length){
                        resolve(v)
                    }                    
                }).catch(reason=>reject(reason))
            }
        })
    }

    static race(promises:any[]):_Promise{
        return new _Promise((resolve,reject)=>{
            for(let p of promises){
                if(p instanceof _Promise){
                    p.then(data=>{
                        resolve(data)
                    }).catch(reason=>reject(reason))
                }else{
                    setTimeout(()=>{
                        resolve(p)
                    })
                }
            }
        })
    }

}

const p = new _Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(99999)
    },15)
})
p.then(data=>{
    console.log(data)
}).catch(reason=>{
    console.error(reason)
})
const pall = _Promise.all([1,2,p,4,43])